const isFunction = (val) => typeof val === 'function';
const isString = (val) => typeof val === 'string';
const isPlainObject = (val)=>typeof val === 'object' && Object.getPrototypeOf(val)===Object.prototype;
var Vuex = {
    Store: function ({ state,getters,mutations,actions,modules }) {
        //先把传入的状态变成响应式对象然后赋值给this.state 
        this.state = Vue.observable(state);
        //初始化子模块对象
        this.modules = modules||{};
        //遍历子模块对象
        for(const moduleName in this.modules){//moduleName=counter
            const module = this.modules[moduleName];//{state:()=>({count:1})}
            //this.state.counter1=
            //先获取 此模块的状态
            const state = isFunction(module.state)?module.state():module.state;
            //把此子模块的状态合并到this.state上
            this.state[moduleName]=Vue.observable(state);
        }

        //初始化actions对象
        this.actions = actions||{};
        //定义一个派发动作的方法，可以派发type类型的动作
        this.dispatch = function(type,payload){
            if(isPlainObject(type)){
                payload=type;//{type:'increment',amount:5}
                type=type.type;//increment
            }
            //通过动作类型找到对应动作函数，执行
            return this.actions[type]?.(this,payload);
        }
        //给仓库实例添加一个commit方法，用于提交变更事件,参数是事件的类型
        this.commit = (type,payload)=>{
            //type={type:'increment',amount:5}
            if(isPlainObject(type)){
                payload=type;//{type:'increment',amount:5}
                type=type.type;//increment
            }
            //根据事件类型在mutations对象中找到对应的函数然后执行
            //你可以向 store.commit 传入额外的参数，即 mutation 的 载荷（payload）
            mutations[type]?.(this.state,payload);
        }
        //初始化仓库自己的getters
        this.getters = {};
        //如果用户传过来了getters
        if(getters){
            //遍历用户传过来的getters
            for(const [key,value] of Object.entries(getters)){
                // 给仓库自己的getters上定义属性，值是一个getter函数
                //函数执行的时候会传递仓库状态和仓库的getters对象
                Object.defineProperty(this.getters,key,{
                    get:()=>{
                        return value(this.state,this.getters);
                    }
                });
            }
        }
    },
    install(Vue) {
        //给全局的Vue添加一个混入选项
        Vue.mixin({
            //添加一个创建前的钩子函数
            beforeCreate() {
                console.log(this);
                //把传递给选项中的store属性赋值给Vue实例的$store
                //这是一全局的混入，所以不管是根实例，还是子组件都会有this.$store
                if (this.$options.store) {
                    this.$store = this.$options.store;
                } else if (this.$parent) {
                    this.$store = this.$parent.$store;
                }
            }
        })
    },
    mapState(map) {
        //声明一个计算属性对象
        let computed = {};
        if (Array.isArray(map)) {
            map.forEach(key=>{
                //定义计算属性，取值去状态对象上取对应的属性
                computed[key] = function () {
                    return this.$store.state[key];
                }
            });
        } else {
            //遍历映射对象
            for (const [key, value] of Object.entries(map)) {
                //key=counter value=state=>state.count
                //判断 value是不是函数
                if (isFunction(value)) {
                    //给computed赋值，属性就是count，值是一个计算值的函数
                    computed[key] = function () {
                        //执行value方法，传入仓库的状态 
                        //this指向Vue实例，$store指向仓库 this.$store.state 指向仓库的状态
                        return value.call(this, this.$store.state);
                    }
                    //如果值是一个字符串的话,表示想要获取仓库状态上的value对应的属性
                } else if (isString(value)) {
                    //computed.countAlias this.$store.state.count 0
                    computed[key] = function () {
                        return this.$store.state[value];
                    }
                }
            }
        }
        return computed;
    },
    mapGetters(getterNames){
        //先声明空的计算属性对象
        let computed = {};
        //遍历要映射的getter的名称数组
        getterNames.forEach(getterName=>{
            //添加新的计算属性，属性名叫 doneTodos
            //值是一个计算函数，在访问属性的时候会执行计算函数获取返回值
            //访问仓库的getters上的属性来获取 对应的值
            computed[getterName]=function(){
                return this.$store.getters[getterName];
            }
        });
        return computed;
    },
    mapMutations(mutationNames){
        const methods = {};
        mutationNames.forEach(mutationName=>{
            methods[mutationName]=function(payload){
                //向仓库提交一个变更，变更的名字就是decrement
                this.$store.commit(mutationName,payload);
            }
        });
        return methods;
    },
    mapActions(actionNames){
        const methods = {};
        actionNames.forEach(actionName=>{
            methods[actionName] = function(payload){
                this.$store.dispatch(actionName,payload);
            }
        });
        return methods;
    }
}